﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using StockTrader.Platform.Charting;
using StockTrader.Platform.Logging;
using StockTrader.Stocks.General;
using StockTrader.Utilities;
using StockTrader.Utilities.Broker;

namespace StockTrader.API.TradingAlgos
{

    public class Algo2_AlgoParams
    {
        public Algo2_AlgoParams(int stockTradingLot,
                          bool bCancelOutstandingOrdersAtStartArg,
                          bool bStartAFreshArg,
                          bool bCancelOutstandingOrdersAtEndArg,
                          double initBidPriceArg,
                          double initOfferPriceArg,
                          bool bMock)
        {
            StockTradingLot = stockTradingLot;
            bCancelOutstandingOrdersAtStart = bCancelOutstandingOrdersAtStartArg;
            bCancelOutstandingOrdersAtStart = bCancelOutstandingOrdersAtStartArg;
            bStartAFresh = bStartAFreshArg;
            initBidPrice = initBidPriceArg;
            initOfferPrice = initOfferPriceArg;
            mMock = bMock;
        }

        // Stock trading lot(qty) for orders
        private int mStockTradingLot;
        public int StockTradingLot
        {
            get { return mStockTradingLot; }
            set { mStockTradingLot = value; }
        }

        public bool bCancelOutstandingOrdersAtStart;
        public bool bCancelOutstandingOrdersAtEnd;
        public bool bStartAFresh;
        public double initBidPrice;
        public double initOfferPrice;
        public bool mMock;
    }

    public class Algo2_BuySellAnalyzer: ITradingAlgo
    {
        List<StockOrder> mOrders = new List<StockOrder>();
        List<DerivativeQuoteInformation> tickList = new List<DerivativeQuoteInformation>();

        double mPercentageChangeForFreshBuy;
        double mPercentageChangeForShortSquareOff;
        double mPercentageChangeForFreshShort;
        double mPercentageChangeForLongSquareOff;

        //if the price moves in the opposite direction (leading to a loss)
        //then mark losses if this is the percentage change.
        double mStopLossPercentage;

        //if the profit percentage is above this price, 
        //then book profit.
        //else, hold on
        double mMinimumProfitPercentage;
        double mBrokerage;
        bool mAllowShort;
        bool mAllowLong;
        double mLongCeilingPrice;
        double mShortFloorPrice;

        int mTickCounter = 0;
        bool bReplayDone = false;

        IBroker mBroker;
        string mStockCode;
        int mQuantity;
        InstrumentType mInstrumentType;
        DateTime mExpiryDate;
        bool mMock;
        bool mIsReplayMode;

        bool mUseProbableTradeValue;
        
        string mFileName;
        string mCummTickFileName;
        string mReplayTickFile;
        TickChart mChart;

        public Algo2_BuySellAnalyzer(
            TickChart chart,
            bool bMock,
            bool bIsReplayMode,
            string replayTickFile,
            string tickFileToBeAppended,
            bool bUseProbableTradeValue,
            double percentageChangeForFreshBuy,
            double percentageChangeForShortSquareOff,
            double percentageChangeForFreshShort,
            double percentageChangeForLongSquareOff,
            double stopLossPercentage,
            double minimumProfitPercentage,
            double brokerage,
            bool allowShort,
            bool allowLong,
            double longCeilingPrice,
            double shortFloorPrice,
            StockOrder startOrder,
            IBroker broker,
            string stockCode,
            int quantity,
            InstrumentType instrumentType,
            DateTime expiryDate)
        {
            mChart = chart;

            mMock = bMock;
            mIsReplayMode = bIsReplayMode;
            mReplayTickFile = replayTickFile;

            mPercentageChangeForFreshBuy = percentageChangeForFreshBuy;
            mPercentageChangeForShortSquareOff = percentageChangeForShortSquareOff;
            mPercentageChangeForFreshShort = percentageChangeForFreshShort;
            mPercentageChangeForLongSquareOff = percentageChangeForLongSquareOff;

            mStopLossPercentage = stopLossPercentage;
            mMinimumProfitPercentage = minimumProfitPercentage;
            
            mBrokerage = brokerage;

            mAllowShort = allowShort;
            mAllowLong = allowLong;

            mLongCeilingPrice = longCeilingPrice;
            mShortFloorPrice = shortFloorPrice;

            mUseProbableTradeValue = bUseProbableTradeValue;

            mOrders.Add(new StockOrder(startOrder));

            mBroker = broker;
            mStockCode = stockCode;
            mQuantity = quantity;
            mInstrumentType = instrumentType;
            mExpiryDate = expiryDate;

            TotalProfit = 0;
            TotalBuyTrades = 0;
            TotalSellTrades = 0;

            mCummTickFileName = "C:\\StockTickFiles\\Ticks-" + mStockCode + ".txt";
            
            if (!string.IsNullOrEmpty(tickFileToBeAppended))
            {
                mFileName = tickFileToBeAppended;
            }
            else
            {
                mFileName = "C:\\StockTickFiles\\Ticks-" + mStockCode + "-" + Guid.NewGuid().ToString() + ".txt";
            }

            FileTracing.TraceOut(string.Format("BSA TickFile = {0}\n", mFileName));
//if (mAllowLong && mAllowShort)
            //{
            //    throw new NotSupportedException("Both Long & Short Positions Not Allowed");
            //}
        }

        private double mTotalProfit;
        public double TotalProfit
        {
            private set { mTotalProfit = value; }
            get
            {
                return mTotalProfit;
            }
        }
        private int mTotalBuyTrades;
        public int TotalBuyTrades
        {
            private set { mTotalBuyTrades = value; }
            get
            {
                return mTotalBuyTrades;
            }
        }
        private int mTotalSellTrades;
        public int TotalSellTrades
        {
            private set { mTotalSellTrades = value; }
            get
            {
                return mTotalSellTrades;
            }
        }

        public double GetPriceForAnalysis(DerivativeQuoteInformation di)
        {
            double price = di.LastTradedPriceDouble;
            if (mUseProbableTradeValue && di.ProbableNextTradeValue != -1)
            {
                price = di.ProbableNextTradeValue;
            }
            return price;
        }

        public void MarketClosing()
        {
            Analyze(true);
        }

        public void AddTick(DerivativeQuoteInformation di)
        {
            double analysisPrice = GetPriceForAnalysis(di);
            DateTime Now = di.UpdateTime;

            di.TickNumber = mTickCounter++;

            // TODO: ideally should be server time when the tick was published
            
            if (!mIsReplayMode)
            {
                string str = Now.ToString("yyyyMMdd:HHmmss") + ";" + di.LastTradedPriceDouble + ";" + di.BidPriceDouble + ";"
                            + di.OfferPriceDouble + ";" + di.BidQuantityInt + ";" + di.OfferQuantityInt;
                
                // Daily stock tick file
                using (FileStream fs = new FileStream(mFileName, FileMode.Append, FileAccess.Write))
                {
                    using (StreamWriter sw = new StreamWriter(fs))
                    {
                        sw.WriteLine(str);
                    }
                }
                
                // Cummulative tick file
                using (FileStream fs = new FileStream(mCummTickFileName, FileMode.Append, FileAccess.Write))
                {
                    using (StreamWriter sw = new StreamWriter(fs))
                    {
                        sw.WriteLine(str);
                    }
                }

            }
            if (mChart != null)
            {
                PointF pNew = new PointF(di.TickNumber, (float)analysisPrice);

                mChart.DrawTickLine(pNew);
            }
            int lastIndex = tickList.Count - 1;
            if ((tickList.Count >= 1) &&
                (GetPriceForAnalysis(di) == GetPriceForAnalysis(tickList[lastIndex])))
            {
                tickList[lastIndex] = di;
            }
            else if ((tickList.Count >= 2) &&
                (GetPriceForAnalysis(tickList[lastIndex]) < GetPriceForAnalysis(tickList[lastIndex - 1])) &&
                (GetPriceForAnalysis(di) < GetPriceForAnalysis(tickList[lastIndex])))
            {
                tickList[lastIndex] = di;
            }
            else if ((tickList.Count >= 2) &&
                (GetPriceForAnalysis(tickList[lastIndex]) > GetPriceForAnalysis(tickList[lastIndex - 1])) &&
                (GetPriceForAnalysis(di) > GetPriceForAnalysis(tickList[lastIndex])))
            {
                tickList[lastIndex] = di;
            }
            else
            {
                tickList.Add(di);
            }
            bool toAnalyze = true;
            while (toAnalyze)
            {
                if (mIsReplayMode)
                {
                    Analyze(false);
                }
                else
                {
                    Analyze(MarketUtils.IsTimeAfter315());
                }
                toAnalyze = CollapsePrices();
            }
        }

        public List<StockOrder> GetCurrentOpenPositions()
        {
            //foreach (Order singleOrder in mOrders)
            //{
            //    FileTracing.TraceOut(singleOrder.ToString());  
            //}

            return mOrders;
        }

        void Analyze(bool marketClosing)
        {
            if (tickList.Count < 2) return;
            int endIndex = tickList.Count - 1;
            double difference = GetPriceForAnalysis(tickList[endIndex]) - GetPriceForAnalysis(tickList[endIndex - 1]);
            double percChange = 100 * difference / GetPriceForAnalysis(tickList[endIndex - 1]);
            foreach (StockOrder singleOrder in mOrders)
            {
                if (marketClosing)
                {
                    PossibleSquareOff(tickList[endIndex], singleOrder);
                }

                //if (Math.Abs(percChange) < mPercentageChangeForMarketDirection)
                //{
                //    //this change is not sufficient to indicate a change in market direction
                //    break;
                //}

                if (percChange > 0)
                {
                    //market is going up
                    if (singleOrder.OrderPosition == Position.Sell)
                    {
                        //already short sold.
                        //either square off for profit, or for loss if the 
                        //percentage change is greater than the stop loss percentage
                        //double buyDiff = GetPriceForAnalysis(tickList[endIndex], Position.Buy) - GetPriceForAnalysis(tickList[endIndex - 1], Position.Buy);
                        //double percChange = 100 * difference / GetPriceForAnalysis(tickList[endIndex - 1]);
                        if (Math.Abs(percChange) > mPercentageChangeForShortSquareOff)
                        {
                            PossibleSquareOff(tickList[endIndex], singleOrder);
                        }
                    }
                    if ((singleOrder.OrderPosition == Position.None))
                    {
                        //buy
                        if (!marketClosing && mAllowLong)
                        {
                            double currentPricePoint = GetPriceForAnalysis(tickList[endIndex]);
                            if (Math.Abs(percChange) > mPercentageChangeForFreshBuy &&
                                (mLongCeilingPrice <= 0 || currentPricePoint <= mLongCeilingPrice))
                            {
                                PlaceOrder(Position.Buy, singleOrder, tickList[endIndex]);
                            }
                        }
                    }
                    if (singleOrder.OrderPosition == Position.Buy)
                    {
                        //already bought
                    }
                }
                else if (percChange < 0)
                {
                    //market is going down.
                    if (singleOrder.OrderPosition == Position.Buy)
                    {
                        //already bought.                           
                        //either square off for profit, or for loss if the 
                        //percentage change is greater than the stop loss percentage
                        if (Math.Abs(percChange) > mPercentageChangeForLongSquareOff)
                        {
                            PossibleSquareOff(tickList[endIndex], singleOrder);
                        }
                    }
                    if ((singleOrder.OrderPosition == Position.None))
                    {
                        //short sell
                        if (!marketClosing && mAllowShort)
                        {
                            double currentPricePoint = GetPriceForAnalysis(tickList[endIndex]);
                            if (Math.Abs(percChange) > mPercentageChangeForFreshShort &&
                                 (mShortFloorPrice <= 0 || currentPricePoint >= mShortFloorPrice))
                            {
                                PlaceOrder(Position.Sell, singleOrder, tickList[endIndex]);
                            }
                        }
                    }
                    if (singleOrder.OrderPosition == Position.Sell)
                    {
                        //already sold
                    }
                }
            }
        }

        bool CollapsePrices()
        {
            if (tickList.Count < 4) return false;
            int endIndex = tickList.Count - 1;
            DerivativeQuoteInformation di4 = tickList[endIndex];
            DerivativeQuoteInformation di3 = tickList[endIndex - 1];
            DerivativeQuoteInformation di2 = tickList[endIndex - 2];
            DerivativeQuoteInformation di1 = tickList[endIndex - 3];

            //Level1 is at a higher level than Level7

            //di1, di2, di3, di4

            //4, 2, 3, 1
            if ((GetPriceForAnalysis(di1) <= GetPriceForAnalysis(di3)) &&
                (GetPriceForAnalysis(di3) <= GetPriceForAnalysis(di2)) &&
                (GetPriceForAnalysis(di2) <= GetPriceForAnalysis(di4)))
            {
                tickList[endIndex - 2] = di4;
                tickList.RemoveRange(endIndex - 1, 2);
                return true;
            }

            //4, 3, 5, 2
            else if ((GetPriceForAnalysis(di3) <= GetPriceForAnalysis(di1)) &&
                (GetPriceForAnalysis(di1) <= GetPriceForAnalysis(di2)) &&
                (GetPriceForAnalysis(di2) <= GetPriceForAnalysis(di4)))
            {
                tickList[endIndex - 2] = di4;
                tickList.RemoveRange(endIndex - 1, 2);
                return true;
            }

            //4, 6, 5, 7
            else if ((GetPriceForAnalysis(di4) <= GetPriceForAnalysis(di2)) &&
                (GetPriceForAnalysis(di2) <= GetPriceForAnalysis(di3)) &&
                (GetPriceForAnalysis(di3) <= GetPriceForAnalysis(di1)))
            {
                tickList[endIndex - 2] = di4;
                tickList.RemoveRange(endIndex - 1, 2);
                return true;
            }

            //4, 5, 3, 6
            else if ((GetPriceForAnalysis(di4) <= GetPriceForAnalysis(di2)) &&
                (GetPriceForAnalysis(di2) <= GetPriceForAnalysis(di1)) &&
                (GetPriceForAnalysis(di1) <= GetPriceForAnalysis(di3)))
            {
                tickList[endIndex - 2] = di4;
                tickList.RemoveRange(endIndex - 1, 2);
                return true;
            }

            return false;
        }

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern Boolean Beep(UInt32 frequency, UInt32 duration);
        bool PlaceOrder(Position position,
            StockOrder singleOrder,
            DerivativeQuoteInformation di)
        {
                                
            BrokerErrorCode errorCode = BrokerErrorCode.Success;

            int tradeQuantity = mQuantity;
            if (position == Position.Buy)
            {
                double orderPrice = di.OfferPriceDouble;// +.05;
                FileTracing.TraceOut(DateTime.Now.ToLongDateString() + "T " + DateTime.Now.ToLongTimeString() + ". Placing order. Position=" + position.ToString() + ". BidPrice=" + orderPrice + ". Quantity=" + tradeQuantity);  
                Beep(100, 50);

                string orderReference = null;
                while (true)
                {
                    if (mMock || mIsReplayMode)
                    {
                        errorCode = BrokerErrorCode.Success;
                    }
                    else
                    {
                        errorCode = mBroker.PlaceDerivativeOrder(mStockCode,
                           tradeQuantity,
                           orderPrice,
                           OrderPriceType.LIMIT,
                           OrderDirection.BUY,
                           mInstrumentType,
                           mExpiryDate,
                           OrderGoodNessType.IOC,
                           out orderReference);
                    }

                    if (errorCode == BrokerErrorCode.NotLoggedIn)
                    {
                        mBroker.LogOut();
                        errorCode = mBroker.CheckAndLogInIfNeeded(true);
                        continue;
                    }
                    if (errorCode == BrokerErrorCode.Success)
                    {
                        break;
                    }
                    throw new Exception("BSA:PlaceOrder:ErrorCode=" + errorCode);
                }
                OrderStatus orderStatus;
                while (true)
                {
                    DateTime fromDate = DateTime.Now;
                    DateTime toDate = DateTime.Now;
                    if (mMock || mIsReplayMode)
                    {
                        orderStatus = OrderStatus.EXECUTED;
                    }
                    else
                    {
                        errorCode = mBroker.GetOrderStatus(orderReference,
                                                mInstrumentType, fromDate, toDate, out orderStatus);
                    }

                    // If fatal error then come out
                    if(LoginUtils.IsErrorFatal(errorCode))
                    {
                        FileTracing.TraceOut("PlaceOrder: Fatal Error " + errorCode.ToString());
                        return false;
                    }
                    if (errorCode.Equals(BrokerErrorCode.Success))
                    {
                        if (orderStatus.Equals(OrderStatus.EXECUTED))
                        {
                            double executionPrice = -1;
                            int retryCount = 0;
                            if (!(mMock || mIsReplayMode))
                            {
                                do
                                {
                                    executionPrice = mBroker.GetTradeExecutionPrice(fromDate, toDate, mInstrumentType, orderReference);
                                } while (executionPrice == -1 && retryCount++ <= 2);
                            }
                            singleOrder.OrderPrice = executionPrice != -1 ? executionPrice : orderPrice;
                                                        
                            PointF pNew = new PointF(di.TickNumber, (float)singleOrder.OrderPrice);
                            TradeExecType tradeType = TradeExecType.None;

                            if (singleOrder.OrderPosition == Position.Sell)
                            {
                                tradeType = TradeExecType.ShortSquareOff;
                                singleOrder.OrderPosition = Position.None;
                            }
                            else if (singleOrder.OrderPosition == Position.None)
                            {
                                tradeType = TradeExecType.FreshLong;
                                singleOrder.OrderPosition = Position.Buy;
                            }
                            TotalBuyTrades++;

                            if (mChart != null)
                            {
                                //mChart.DrawTradePoint(pNew, singleOrder.ToString(), (GraphDirection)tradeType);
                            }
                            FileTracing.TraceOut("Trade Confirmed");
                            return true;
                        }

                        if (orderStatus == OrderStatus.REJECTED ||
                            orderStatus == OrderStatus.CANCELLED ||
                            orderStatus == OrderStatus.EXPIRED)
                        {
                            FileTracing.TraceOut("No Trade");
                            return false;
                        }
                    }
                }
            }
            else if (position == Position.Sell)
            {
                double orderPrice = di.BidPriceDouble;// -.05;
                //FileTracing.TraceOut(DateTime.Now.ToLongDateString() + "T" + DateTime.Now.ToLongTimeString() + ". Placing order. Position=" + position.ToString() + ". OfferPrice=" + orderPrice + ". Quantity=" + tradeQuantity);
                FileTracing.TraceOut(DateTime.Now.ToLongDateString() + "T" + DateTime.Now.ToLongTimeString() + ". Placing order. Position=" + position.ToString() + ". OfferPrice=" + orderPrice + ". Quantity=" + tradeQuantity);
                Beep(100, 50);

                string orderReference = null;
                while (true)
                {
                    if (mMock || mIsReplayMode)
                    {
                        errorCode = BrokerErrorCode.Success;
                    }
                    else
                    {
                        errorCode = mBroker.PlaceDerivativeOrder(mStockCode,
                                               tradeQuantity,
                                               orderPrice,
                                               OrderPriceType.LIMIT,
                                               OrderDirection.SELL,
                                               mInstrumentType,
                                               mExpiryDate,
                                               OrderGoodNessType.IOC,
                                               out orderReference);
                    }
                    if (errorCode == BrokerErrorCode.NotLoggedIn)
                    {
                        mBroker.LogOut();
                        errorCode = mBroker.CheckAndLogInIfNeeded(true);
                        continue;
                    }
                    if (errorCode == BrokerErrorCode.Success)
                    {
                        break;
                    }
                    throw new Exception("BSA:PlaceOrder:ErrorCode=" + errorCode);
                }

                OrderStatus orderStatus;
                while (true)
                {
                    DateTime fromDate = DateTime.Now;
                    DateTime toDate = DateTime.Now;

                    // Incase of mock or testing replay
                    if (mMock || mIsReplayMode)
                    {
                        orderStatus = OrderStatus.EXECUTED;
                    }
                    else
                    {
                        errorCode = mBroker.GetOrderStatus(orderReference,
                                                mInstrumentType, fromDate, toDate, out orderStatus);
                    }

                    // If fatal error then come out
                    if (LoginUtils.IsErrorFatal(errorCode))
                    {
                        FileTracing.TraceOut("PlaceOrder: Fatal Error " + errorCode.ToString());
                        return false;
                    }

                    if (errorCode.Equals(BrokerErrorCode.Success))
                    {
                        if (orderStatus.Equals(OrderStatus.EXECUTED))
                        {
                            double executionPrice = -1;
                            int retryCount = 0;


                            if (!(mMock || mIsReplayMode))
                            {
                                // Get actual execution price
                                do
                                {
                                    executionPrice = mBroker.GetTradeExecutionPrice(fromDate, toDate, mInstrumentType, orderReference);
                                } while (executionPrice == -1 && retryCount++ <= 2);
                            }
                            singleOrder.OrderPrice = executionPrice != -1 ? executionPrice : orderPrice;
                            
                            PointF pNew = new PointF(di.TickNumber, (float)singleOrder.OrderPrice);
                            TradeExecType tradeType = TradeExecType.None;

                            if (singleOrder.OrderPosition == Position.Buy)
                            {
                                tradeType = TradeExecType.LongSquareOff;
                                singleOrder.OrderPosition = Position.None;
                            }
                            else if (singleOrder.OrderPosition == Position.None)
                            {
                                tradeType = TradeExecType.FreshShort;
                                singleOrder.OrderPosition = Position.Sell;
                            }

                            TotalSellTrades++;

                            if (mChart != null)
                            {
                                //mChart.DrawTradePoint(pNew, singleOrder.ToString(), tradeType);
                            }
                            FileTracing.TraceOut("Trade Confirmed");
                            return true;
                        }
                        if (orderStatus == OrderStatus.REJECTED ||
                            orderStatus == OrderStatus.CANCELLED ||
                            orderStatus == OrderStatus.EXPIRED)
                        {
                            FileTracing.TraceOut("No Trade");
                            return false;
                        }
                    }
                }
            }
            else
            {
                throw new NotSupportedException("Position=" + position);
            }
        }

        //returns true if an order was placed
        //false if no order was placed - either due to loss percentage being
        //too small, or profit percentage being too small
        void PossibleSquareOff(DerivativeQuoteInformation di, StockOrder singleOrder)
        {
            if (singleOrder.OrderPosition == Position.None)
            {
                return;
            }
            if (singleOrder.OrderPosition == Position.Buy)
            {
                double profitAmount = di.BidPriceDouble - singleOrder.OrderPrice;
                if (profitAmount > 0)
                {
                    double profitPerc = 100 * (profitAmount / singleOrder.OrderPrice);
                    if (profitPerc > mMinimumProfitPercentage)
                    {
                        if (PlaceOrder(Position.Sell, singleOrder, di))
                        {
                            mTotalProfit += profitAmount;
                            FileTracing.TraceOut("Profit/Loss Amount = " + profitAmount);
                        }
                        return;
                    }
                    else
                    {
                        return;
                    }
                }
                else if (profitAmount == 0)
                {
                    return;
                }
                else if (profitAmount < 0)
                {
                    double lossPerc = -100 * (profitAmount / singleOrder.OrderPrice);
                    if (lossPerc > mStopLossPercentage)
                    {
                        if (PlaceOrder(Position.Sell, singleOrder, di))
                        {
                            mTotalProfit += profitAmount;
                            FileTracing.TraceOut("Profit/Loss Amount = " + profitAmount);
                        }
                    }
                    return;
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
            else if (singleOrder.OrderPosition == Position.Sell)
            {
                double profitAmount = singleOrder.OrderPrice - di.OfferPriceDouble;
                if (profitAmount > 0)
                {
                    double profitPerc = 100 * profitAmount / di.OfferPriceDouble;
                    if (profitPerc > mMinimumProfitPercentage)
                    {
                        if (PlaceOrder(Position.Buy, singleOrder, di))
                        {
                            mTotalProfit += profitAmount;
                            FileTracing.TraceOut("Profit/Loss Amount = " + profitAmount);
                        }
                        return;
                    }
                    else
                    {
                        return;
                    }
                }
                else if (profitAmount == 0)
                {
                    return;
                }
                else if (profitAmount < 0)
                {
                    double lossPerc = -100 * (profitAmount / singleOrder.OrderPrice);
                    if (lossPerc > mStopLossPercentage)
                    {
                        if (PlaceOrder(Position.Buy, singleOrder, di))
                        {
                            mTotalProfit += profitAmount;
                            FileTracing.TraceOut("Profit/Loss Amount = " + profitAmount);
                        }
                    }
                    return;
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
            else
            {
                throw new NotSupportedException();
            }
        }


        public BrokerErrorCode Prolog()
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            string traceString = "----- Starting MKD_FutureTrader Thread ----- \n";
             
            traceString += "Algo2_BuySellAnalyzer.Prolog :: ENTER";

            FileTracing.TraceOut(traceString);

            errorCode = mBroker.CheckAndLogInIfNeeded(false);
            if (errorCode != BrokerErrorCode.Success)
            {
                FileTracing.TraceOut("ERROR: LogIn(). BrokerErrorCode=" + errorCode.ToString());
            }

            traceString = "Algo2_BuySellAnalyzer.Prolog :: EXIT";
            FileTracing.TraceOut(traceString);

            return errorCode;
        }

        public BrokerErrorCode RunCoreAlgo()
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            // replay bsa text file
            if (mIsReplayMode)
            {
                if (!bReplayDone)
                {
                    #region ReplayBSATicksFile
                    bReplayDone = true;
                    using (FileStream fs = new FileStream(mReplayTickFile, FileMode.Open, FileAccess.Read))
                    {
                        using (StreamReader sr = new StreamReader(fs))
                        {
                            string s = null;
                            do
                            {
                                //s = sr.ReadLine(); // inital description strings, ignore them
                                s = sr.ReadLine();
                                if (s != null)
                                {
                                    string[] parts = s.Split(';');
                                    AddTick(new DerivativeQuoteInformation(
                                        double.Parse(parts[1]),
                                        double.Parse(parts[2]),
                                        double.Parse(parts[3]),
                                        int.Parse(parts[4]),
                                        int.Parse(parts[5])
                                        ));//,false);
                                }
                            } while (s != null);
                        }
                    }
                    #endregion
                }
            }
            else
            {
                #region ActualAlgoLoop
                // run bsa analyzer in loop
                DerivativeQuoteInformation di;
                errorCode = mBroker.GetDerivativeQuote(mStockCode,
                     mInstrumentType,
                     mExpiryDate,
                     0,
                     out di);
                if (errorCode.Equals(BrokerErrorCode.Success))
                {
                    AddTick(di);
                }
                else
                {
                    FileTracing.TraceOut("MKD_FutureTrader: " + errorCode.ToString());
                }
                #endregion
            }
            return errorCode;
        }

        public BrokerErrorCode Epilog()
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            string traceString;
            traceString = "Total Trades : \n" + "Buy: " + TotalBuyTrades + ", Sell: " + TotalSellTrades + "\n";
            double tradeBrokerage = mBrokerage / 2 * (TotalBuyTrades + TotalSellTrades);
            traceString += "Total brokerage : " + tradeBrokerage + "\n";
            traceString += "Total Profit (after brokerage) : " + (TotalProfit - tradeBrokerage).ToString() + "\n";
            traceString += "Current open positions:\n";
            foreach (StockOrder o in GetCurrentOpenPositions())
            {
                traceString += "OrderDetails: " + o.ToString() + "\n";
            }
            traceString += "----- Exiting MKD_FutureTrader Thread ----- \n";
            FileTracing.TraceOut(traceString);
            return errorCode;
        }

        public int GetSleepTimeInMilliSecs()
        {
            // 0.7 second sleep
            return 700;
        }
 
    }
          
}
